package com.yckj.activechicken.business.hr.service.impl;

import com.yckj.activechicken.business.hr.mapper.HrEmployeeMapper;
import com.yckj.activechicken.business.hr.mapper.HrLeaveMapper;
import com.yckj.activechicken.business.hr.mapper.comp.HrLeaveMapperComp;
import com.yckj.activechicken.business.hr.model.HrEmployee;
import com.yckj.activechicken.business.hr.model.HrLeave;
import com.yckj.activechicken.business.hr.model.vo.HrLeaveVo;
import com.yckj.activechicken.business.hr.service.IHrLeaveService;
import com.yckj.activechicken.business.system.mapper.SysDeptMapper;
import com.yckj.activechicken.business.system.model.SysDept;
import com.yckj.activechicken.business.system.model.SysDeptExample;
import com.yckj.activechicken.business.system.model.SysUser;
import com.yckj.activechicken.common.utils.StringUtils;
import com.yckj.activechicken.common.utils.security.SecurityUtils;
import com.yckj.activechicken.framework.aspectj.lang.annotation.DataScope;
import com.yckj.activechicken.framework.security.model.LoginUser;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * Title:com.yckj.activechicken.business.hr.service.impl
 * </p>
 * <p/>
 * <p>
 * Description: 描述【请假管理业务处理实体】
 * </p>
 * <p/>
 * <p>
 * Copyright: Copyright (c) 2019
 * </p>
 * <p/>
 * <p>
 * Company: 英才汇硕信息技术有限公司
 * </p>
 *
 * @author zhoujy
 * @version 1.0
 * @created 2020/5/25 15:03
 */
@Service
public class HrLeaveServiceImpl implements IHrLeaveService {
    @Autowired
    private HrLeaveMapper hrLeaveMapper;

    @Autowired
    private HrLeaveMapperComp hrLeaveMapperComp;

    @Autowired
    private HrEmployeeMapper hrEmployeeMapper;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private SysDeptMapper sysDeptMapper;


    /**
     * 添加请假单，草稿信息
     *
     * @param hrLeave
     * @return
     */
    @Override
    public int addLeave(HrLeave hrLeave) {
        //根据员工id获取真实的员工姓名
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser sysUser = loginUser.getUser();
        int empId = sysUser.getEmpId();
        HrEmployee hrEmployee = hrEmployeeMapper.selectByPrimaryKey(empId);
        hrLeave.setApplyName(hrEmployee.getName());
        //添加记录
        return hrLeaveMapper.insertSelective(hrLeave);
    }

    /**
     * 修改请假单，草稿信息
     *
     * @param hrLeave
     * @return
     */
    @Override
    public int modifyLeave(HrLeave hrLeave) {
        return hrLeaveMapper.updateByPrimaryKeySelective(hrLeave);
    }

    /**
     * 添加请假单，并发起请假审批流程
     *
     * @param hrLeave
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int addAndApplyLeave(HrLeave hrLeave) {
        /*
         * 1、添加请假单信息
         */
        //根据员工id获取真实的员工姓名
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser sysUser = loginUser.getUser();
        int empId = sysUser.getEmpId();
        HrEmployee hrEmployee = hrEmployeeMapper.selectByPrimaryKey(empId);
        hrLeave.setApplyName(hrEmployee.getName());
        hrLeaveMapper.insertSelective(hrLeave);
        //请假单号
        Integer leaveId = hrLeave.getLeaveId();

        /*
         * 2、获取该用户的部门领导，将其以流程变量的方式设置为部门审批人
         */
        //获取当前申请人所在部门的领导信息
        String leader = sysUser.getDept().getLeader();
        Map<String, Object> variables = new HashMap<>();
        variables.put("deptUser", leader);
        //以流程定义key启动流程实例，并设置流程变量，把请假单号作为businessKey传入
        ProcessInstance leaveProcess1 = runtimeService.startProcessInstanceByKey("LeaveProcess1", leaveId.toString(), variables);

        /*
         * 3、更新请假信息，将流程实例id存入请假单中
         */
        int resultNum = 0;
        if (leaveProcess1 != null) {
            hrLeave.setInstanceId(leaveProcess1.getProcessInstanceId());
            resultNum = hrLeaveMapper.updateByPrimaryKeySelective(hrLeave);
        }


        return resultNum;
    }

    /**
     * 发起假单申请
     * @param hrLeave
     * @return
     */
    @Override
    public int applyLeave(HrLeave hrLeave) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser sysUser = loginUser.getUser();
        //请假单号
        Integer leaveId = hrLeave.getLeaveId();

        /*
         * 2、获取该用户的部门领导，将其以流程变量的方式设置为部门审批人
         */
        //获取当前申请人所在部门的领导信息
        String leader = sysUser.getDept().getLeader();
        Map<String, Object> variables = new HashMap<>();
        variables.put("deptUser", leader);
        //以流程定义key启动流程实例，并设置流程变量，把请假单号作为businessKey传入
        ProcessInstance leaveProcess1 = runtimeService.startProcessInstanceByKey("LeaveProcess1", leaveId.toString(), variables);

        /*
         * 3、更新请假信息，将流程实例id存入请假单中
         */
        int resultNum = 0;
        if (leaveProcess1 != null) {
            hrLeave.setInstanceId(leaveProcess1.getProcessInstanceId());
            resultNum = hrLeaveMapper.updateByPrimaryKeySelective(hrLeave);
        }


        return resultNum;
    }

    /**
     * 多条件查询假单信息列表
     *
     * @param hrLeave
     * @return
     */
    @Override
    @DataScope(deptAlias = "d", userAlias = "u")
    public List<HrLeave> queryLeaveList(HrLeave hrLeave) {
        return hrLeaveMapperComp.selectLeaveList(hrLeave);
    }

    /**
     * 带条件查询待办列表
     *
     * @param hrLeave
     * @return
     */
    @Override
    public List<HrLeaveVo> queryTodoLeaveList(HrLeave hrLeave) {
        List<HrLeaveVo> hrLeaveVoList = new ArrayList<>();

        //获取当前操作者用户名
        String username = SecurityUtils.getUsername();
        //获取待办列表
        List<Task> taskList = taskService.createTaskQuery().processDefinitionKey("LeaveProcess1").taskAssignee(username).list();

        if (StringUtils.isNotEmpty(taskList)) {
            for (Task task : taskList) {
                //获取当前任务的业务处理id，businessKey
                String processInstanceId = task.getProcessInstanceId();
                ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                        .processInstanceId(processInstanceId).singleResult();
                String businessKey = processInstance.getBusinessKey();

                //根据业务处理id查询请假单信息
                HrLeave outHrLeave = hrLeaveMapper.selectByPrimaryKey(Integer.parseInt(businessKey));

                //判断第一个条件，假单类型
                if (StringUtils.isNotBlank(hrLeave.getType()) && !outHrLeave.getType().equals(hrLeave.getType())) {
                    continue;
                }

                //判断第二个条件，申请人
                if (StringUtils.isNotBlank(hrLeave.getApplyName()) && !outHrLeave.getApplyName().equals(hrLeave.getApplyName())) {
                    continue;
                }

                //将假单信息拷贝输入对象中去
                HrLeaveVo hrLeaveVo = new HrLeaveVo();
                BeanUtils.copyProperties(outHrLeave, hrLeaveVo);
                hrLeaveVo.setProcessInstanceId(processInstanceId);
                hrLeaveVo.setTaskId(task.getId());
                hrLeaveVo.setTaskName(task.getName());

                hrLeaveVoList.add(hrLeaveVo);
            }
        }

        return hrLeaveVoList;
    }


    /**
     * 审批假单，存在部门审批和人事审批两种情况
     *
     * @param hrLeaveVo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int approvalLeave(HrLeaveVo hrLeaveVo) {
        //获取基本的环节处理信息
        String processInstanceId = hrLeaveVo.getProcessInstanceId();
        String taskId = hrLeaveVo.getTaskId();
        String taskName = hrLeaveVo.getTaskName();
        String approval = hrLeaveVo.getApproval();
        String approvalComment = hrLeaveVo.getApprovalComment();

        int resultNum = 0;

        if ("部门领导审批".equals(taskName)) {
            if ("同意".equals(approval)) {
                //获取下一环节审批人信息，获取同一公司下的人力资源部门领导用户名
                LoginUser loginUser = SecurityUtils.getLoginUser();
                SysDept dept = loginUser.getUser().getDept();
                Integer parentId = dept.getParentId();
                SysDeptExample sysDeptExample = new SysDeptExample();
                sysDeptExample.createCriteria().andParentIdEqualTo(parentId).andDeptNameEqualTo("人力资源部");
                List<SysDept> sysDeptList = sysDeptMapper.selectByExample(sysDeptExample);
                if (StringUtils.isNotEmpty(sysDeptList)) {
                    //获取的人力资源部门领导名
                    String leader = sysDeptList.get(0).getLeader();
                    //处理该环节的审批
                    Map<String, Object> variable = new HashMap<>();
                    variable.put("approval", approval);
                    variable.put("hrUser", leader);
                    //添加批注，taskId,processInstance,message
                    taskService.addComment(taskId, processInstanceId, approval+":"+approvalComment);
                    taskService.complete(taskId, variable);
                    resultNum = 1;
                }
            } else {
                //不同意的处理逻辑，打回给申请人
                //处理该环节的审批
                Map<String, Object> variable = new HashMap<>();
                variable.put("approval", approval);
                variable.put("applyUser", hrLeaveVo.getApplyUser());
                //添加批注，taskId,processInstance,message
                taskService.addComment(taskId, processInstanceId, approval+":"+approvalComment);
                taskService.complete(taskId, variable);

                //更新请假单状态为已驳回
                HrLeave hrLeave = new HrLeaveVo();
                hrLeave.setLeaveId(hrLeaveVo.getLeaveId());
                hrLeave.setStatus("已驳回");
                resultNum = hrLeaveMapper.updateByPrimaryKeySelective(hrLeave);
            }
        } else if ("人事审批".equals(taskName)) {
            if ("同意".equals(approval)) {
                //处理该环节的审批
                Map<String, Object> variable = new HashMap<>();
                variable.put("approval", approval);
                //添加批注，taskId,processInstance,message
                taskService.addComment(taskId, processInstanceId, approval+":"+approvalComment);
                taskService.complete(taskId, variable);

                //判断流程是否正常结束
                ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                        .processInstanceId(processInstanceId).singleResult();
                if (processInstance == null) {
                    //更新请假单状态为已驳回
                    HrLeave hrLeave = new HrLeaveVo();
                    hrLeave.setLeaveId(hrLeaveVo.getLeaveId());
                    hrLeave.setStatus("已同意");
                    resultNum = hrLeaveMapper.updateByPrimaryKeySelective(hrLeave);
                }
            } else {
                //不同意的处理逻辑，打回给申请人
                //处理该环节的审批
                Map<String, Object> variable = new HashMap<>();
                variable.put("approval", approval);
                variable.put("applyUser", hrLeaveVo.getApplyUser());
                //添加批注，taskId,processInstance,message
                taskService.addComment(taskId, processInstanceId, approval+":"+approvalComment);
                taskService.complete(taskId, variable);

                //更新请假单状态为已驳回
                HrLeave hrLeave = new HrLeaveVo();
                hrLeave.setLeaveId(hrLeaveVo.getLeaveId());
                hrLeave.setStatus("已驳回");
                resultNum = hrLeaveMapper.updateByPrimaryKeySelective(hrLeave);
            }
        }

        return resultNum;
    }

    /**
     * 放弃请假申请
     * @param hrLeaveVo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int giveUpLeave(HrLeaveVo hrLeaveVo) {
        //获取基本的环节处理信息
        String processInstanceId = hrLeaveVo.getProcessInstanceId();
        String taskId = hrLeaveVo.getTaskId();
        int resultNum = 0;

        Map<String, Object> variable = new HashMap<>();
        variable.put("option", "放弃");
        //添加批注，taskId,processInstance,message
        taskService.addComment(taskId, processInstanceId, "放弃:"+"放弃请假申请");
        taskService.complete(taskId, variable);

        //判断流程是否正常结束
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
        if (processInstance == null) {
            //更新请假单状态为已驳回
            HrLeave hrLeave = new HrLeaveVo();
            hrLeave.setLeaveId(hrLeaveVo.getLeaveId());
            hrLeave.setStatus("已放弃");
            resultNum = hrLeaveMapper.updateByPrimaryKeySelective(hrLeave);
        }

        return resultNum;
    }

    /**
     * 修改假单，之后重新发起申请
     * @param hrLeaveVo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int modifyAndApplyLeave(HrLeaveVo hrLeaveVo) {
        //处理流程，重新发起申请
        String processInstanceId = hrLeaveVo.getProcessInstanceId();
        String taskId = hrLeaveVo.getTaskId();
        int resultNum = 0;

        LoginUser loginUser = SecurityUtils.getLoginUser();
        SysUser sysUser = loginUser.getUser();
        String leader = sysUser.getDept().getLeader();

        Map<String, Object> variable = new HashMap<>();
        variable.put("option", "调整");
        variable.put("deptUser", leader);
        //添加批注，taskId,processInstance,message
        taskService.addComment(taskId, processInstanceId, "调整:"+"添加假单发起申请");
        taskService.complete(taskId, variable);

        //更新请假单信息
        HrLeave hrLeave = new HrLeave();
        BeanUtils.copyProperties(hrLeaveVo,hrLeave);
        hrLeave.setStatus("审批中");
        int num = hrLeaveMapper.updateByPrimaryKeySelective(hrLeave);

        return num;
    }

    /**
     * 带条件查询已办列表
     * @param hrLeave
     * @return
     */
    @Override
    public List<HrLeaveVo> queryHistoryLeaveList(HrLeave hrLeave) {
        String username = SecurityUtils.getUsername();
        List<HrLeaveVo> results = new ArrayList<>();
        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
                .processDefinitionKey("LeaveProcess1")
                .taskAssignee(username)
                .finished()
                .orderByHistoricTaskInstanceEndTime()
                .desc()
                .list();

        if(StringUtils.isNotEmpty(list)){
            for(HistoricTaskInstance historicTaskInstance : list){
                //通过历史任务实例信息获取流程实例id
                String processInstanceId = historicTaskInstance.getProcessInstanceId();
                //通过流程实例id获取历史流程实例信息
                HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                        .processInstanceId(processInstanceId).singleResult();
                //获取业务id
                String businessKey = historicProcessInstance.getBusinessKey();

                //获取请假单详情
                HrLeave outHrLeave = hrLeaveMapper.selectByPrimaryKey(Integer.parseInt(businessKey));

                //判断第一个条件，假单类型
                if (StringUtils.isNotBlank(hrLeave.getType()) && !outHrLeave.getType().equals(hrLeave.getType())) {
                    continue;
                }

                //判断第二个条件，申请人
                if (StringUtils.isNotBlank(hrLeave.getApplyName()) && !outHrLeave.getApplyName().equals(hrLeave.getApplyName())) {
                    continue;
                }

                //将假单信息拷贝输入对象中去
                HrLeaveVo hrLeaveVo = new HrLeaveVo();
                BeanUtils.copyProperties(outHrLeave, hrLeaveVo);
                hrLeaveVo.setTaskId(historicTaskInstance.getId());
                hrLeaveVo.setTaskName(historicTaskInstance.getName());
                //办理时间
                hrLeaveVo.setDoneTime(historicTaskInstance.getEndTime());

                results.add(hrLeaveVo);

            }
        }

        return results;
    }
}
